package jee.boot.data.permission.interceptor;

import jee.boot.common.basic.ServiceException;
import jee.boot.common.basic.result.MapData;
import jee.boot.common.properties.PermitUrlProperties;
import jee.boot.common.standard.AccountHandler;
import jee.boot.common.standard.AuthorityHandler;
import jee.boot.common.utils.StringUtils;
import jee.boot.data.permission.config.PassCheckConfig;
import jee.boot.entity.auth.AuthEntity;
import jee.boot.entity.auth.ModelData;
import jee.boot.entity.auth.Resource;
import jee.boot.entity.auth.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;


/**
 * Request权限检查
 */
@Component
public class RequestCheckInterceptor implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(RequestCheckInterceptor.class);
    private AntPathMatcher matcher = new AntPathMatcher();
    @Autowired
    private AuthorityHandler authorityHandler;
    @Autowired
    private PermitUrlProperties permitUrlProperties;
    @Autowired
    private AccountHandler accountHandler;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String path = request.getRequestURI();
        User user = (User) authorityHandler.getCurrentUser();
        // 跳过静态资源,直接放行
        if (StringUtils.startsWith(path, "/static/")) {
            return true;
        }

        // 白名单,直接放行
        if (checkPermitUrl(path)) {
            return true;
        }
        // 获取放行的URI
        if (PassCheckConfig.getPassUriList().contains(path)) {
            return true;
        }
        // 超级管理员,直接放行
        if (accountHandler.isSuperAdministrator()) {
            return true;
        }
        // 检查模型请求,如果匹配成功,则按/standardModel/{modelCode}/**来检查模型的操作请求权限
        if (StringUtils.startsWith(path, "/standardModel/")) {
            if (!checkModelPermission(user, path)) {
                // 未授权的请求
                throw new ServiceException(1204, MapData.instance().put("path",path).data());
            }else{
                return true;
            }
        }
        // 检查访问权限
        if (!checkPermission(user, path)) {
            // 未授权的请求
            throw new ServiceException(1205, MapData.instance().put("path",path).data());
        }

        return true;
    }

    /**
     * 检查模型是否已经授权
     *
     * @param user
     * @param path
     * @return
     */
    private boolean checkModelPermission(User user, String path) {
        if (user == null) {
            return false;
        }
        List<AuthEntity> modelDataList = user.getModelDataList();
        if (modelDataList == null || modelDataList.isEmpty()) {
            return false;
        }
        for (AuthEntity model : modelDataList) {
            String code = ((ModelData) model.getEntity()).getCode();
            String modelPath = "/standardModel/" + code + "/**";
            // 匹配上,放行
            if (matcher.match(modelPath, path)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查权限
     *
     * @param user
     * @param path
     * @return
     */
    private boolean checkPermission(User user, String path) {
        if (user == null) {
            return false;
        }
        Map<String, Resource> requestMap = user.getRequestMap();
        if (requestMap == null || requestMap.isEmpty()) {
            return false;
        }
        for (Resource request : requestMap.values()) {
            // 匹配上,放行
            if (matcher.match(request.getName(), path)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查请求是否在放行的白名单中
     *
     * @param path
     * @return
     */
    private boolean checkPermitUrl(String path) {
        for (String s : permitUrlProperties.getOauthUrls()) {
            if (matcher.match(s, path)) {
                return true;
            }
        }
        for (String s : permitUrlProperties.getHttpUrls()) {
            if (matcher.match(s, path)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }


}
